package com.wxj.bank.storage.service.impl;

import com.wxj.bank.module.utils.JsonUtils;
import com.wxj.bank.storage.service.IRedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author shengtao
 * @Description: redis工具类
 * @date 2019/01/31 19:15
 */
@Service
public class RedisServiceImpl implements IRedisService,InitializingBean{

    @Autowired
    private StringRedisTemplate redisTemplate;

    private ValueOperations<String,String> stringOperations;

    private ListOperations<String,String> listOperations;

    private SetOperations<String,String> setOperations;

    private HashOperations<String,String,String> hashOperations;

    private ZSetOperations<String,String> zSetOperations;


    @Override
    public Set<String> keys(String patten) {
        return redisTemplate.keys(patten);
    }

    @Override
    public void set(String key, Object obj) {
        stringOperations.set(key, JsonUtils.obj2Json(obj));
    }

    @Override
    public void set(String key, Object obj, long time, TimeUnit timeUnit) {
        stringOperations.set(key,JsonUtils.obj2Json(obj),time,timeUnit);
    }

    @Override
    public <T> T get(String key, Class<T> tClass) {
        String value = stringOperations.get(key);
        if(StringUtils.isNotBlank(value)){
            return JsonUtils.json2Obj(value,tClass);
        }
        return null;
    }

    @Override
    public <T> List<T> multiGet(Collection<String> keys, Class<T> tClass) {
        List<String> values = stringOperations.multiGet(keys);
        List<T> result = values.stream().map(value -> JsonUtils.json2Obj(value,tClass)).collect(toList());
        return result;
    }

    @Override
    public void leftPush(String key, Object... objs) {
        List<String> values = new ArrayList<>();
        for (Object obj:objs){
            values.add(JsonUtils.obj2Json(obj));
        }
        listOperations.leftPushAll(key,values);
    }

    @Override
    public <T> T lGet(String key, long index, Class<T> tClass) {
        String value = listOperations.index(key,index);
        if(StringUtils.isNotBlank(value)){
            return JsonUtils.json2Obj(value,tClass);
        }
        return null;
    }

    @Override
    public <T> List<T> lrange(String key, long begin, long end, Class<T> tClass) {
        List<String> values = listOperations.range(key,begin,end);
        List<T> result = values.stream().map(value -> JsonUtils.json2Obj(value,tClass)).collect(toList());
        return result;
    }

    @Override
    public void put(String key, String hashkey, String value) {
        hashOperations.put(key,hashkey,value);
    }

    @Override
    public void putAll(String key, Map<String, String> values) {
        hashOperations.putAll(key,values);
    }

    @Override
    public <T> T getH(String key, String hashkey,Class<T> tClass) {
        String json = hashOperations.get(key,hashkey);
        if(StringUtils.isNotBlank(json)){
            return JsonUtils.json2Obj(json,tClass);
        }
        return null;
    }

    @Override
    public <T> List<T> multiGetH(String key, Collection<String> keys,Class<T> tClass) {
        return null;
    }

    @Override
    public void deleteH(String key, String hashksy) {
        hashOperations.delete(key,hashksy);
    }

    @Override
    public void zadd(String key, String value, Double score) {
        zSetOperations.add(key,value,score);
    }

    @Override
    public void zaddCollections(String key, Map<String, Double> values) {
        Set<ZSetOperations.TypedTuple<String>> lists = new HashSet<>();
        for (String v:values.keySet()){
            lists.add(new DefaultTypedTuple<>(v,values.get(v)));
        }
        zSetOperations.add(key,lists);
    }

    @Override
    public <T> Map<String, Double> rangeWithScore(String key, long start, long end,Class<T> tClass) {
        Set<ZSetOperations.TypedTuple<String>> values = zSetOperations.rangeWithScores(key,start,end);
        Map<String,Double> results = values.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue,ZSetOperations.TypedTuple::getScore,(k1,k2)->k1));
        return results;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        stringOperations = redisTemplate.opsForValue();
        listOperations = redisTemplate.opsForList();
        setOperations = redisTemplate.opsForSet();
        hashOperations = redisTemplate.opsForHash();
        zSetOperations = redisTemplate.opsForZSet();
    }

}
